Import and process data
df_gpt3.5 <- read_model("gpt-3.5-turbo-1106", icd = FALSE)
df_gpt4.0 <- read_model("gpt-4-turbo-preview", icd = FALSE)
df_claude3_haiku_t1.0 <- read_model("claude-3-haiku-20240307_t1-0", icd = FALSE)
df_claude3_opus_t1.0 <- read_model("claude-3-opus-20240229_t1-0", icd = FALSE)
df_gemini1.0_pro_t1.0 <- read_model("gemini-1.0-pro-002_t1-0", icd = FALSE)
df_gemini1.5_pro_t1.0 <- read_model("gemini-1.5-pro-001_t1-0", icd = FALSE)
df_gpt3.5_icd <- read_model("gpt-3.5-turbo-1106", icd = TRUE)
df_gpt4.0_icd <- read_model("gpt-4-turbo-preview", icd = TRUE)
df_claude3_haiku_t1.0_icd <- read_model("claude-3-haiku-20240307_t1-0", icd = TRUE)
df_claude3_opus_t1.0_icd <- read_model("claude-3-opus-20240229_t1-0", icd = TRUE)
df_gemini1.0_pro_t1.0_icd <- read_model("gemini-1.0-pro-002_t1-0", icd = TRUE)
df_gemini1.5_pro_t1.0_icd <- read_model("gemini-1.5-pro-001_t1-0", icd = TRUE)
# Tally each pair of co-occuring diagnoses within each criteria
# Original responses
df_gpt3.5_codiag <- create_codiagnosis_df(df_gpt3.5, remove_singletons = T)
df_gpt4.0_codiag <- create_codiagnosis_df(df_gpt4.0, remove_singletons = T)
df_claude3_haiku_t1.0_codiag <- create_codiagnosis_df(df_claude3_haiku_t1.0, remove_singletons = T)
df_claude3_opus_t1.0_codiag <- create_codiagnosis_df(df_claude3_opus_t1.0, remove_singletons = T)
df_gemini1.0_pro_t1.0_codiag <- create_codiagnosis_df(df_gemini1.0_pro_t1.0, remove_singletons = T)
df_gemini1.5_pro_t1.0_codiag <- create_codiagnosis_df(df_gemini1.5_pro_t1.0, remove_singletons = T)
# ICD converted responses
df_gpt3.5_icd_codiag <- create_codiagnosis_df(df_gpt3.5_icd, remove_singletons = T)
df_gpt4.0_icd_codiag <- create_codiagnosis_df(df_gpt4.0_icd, remove_singletons = T)
df_claude3_haiku_t1.0_icd_codiag <- create_codiagnosis_df(df_claude3_haiku_t1.0_icd, remove_singletons = T)
df_claude3_opus_t1.0_icd_codiag <- create_codiagnosis_df(df_claude3_opus_t1.0_icd, remove_singletons = T)
df_gemini1.0_pro_t1.0_icd_codiag <- create_codiagnosis_df(df_gemini1.0_pro_t1.0_icd, remove_singletons = T)
df_gemini1.5_pro_t1.0_icd_codiag <- create_codiagnosis_df(df_gemini1.5_pro_t1.0_icd, remove_singletons = T)
df_gpt4.0_codiag
Plot centrality
calculate_subgraph_centrality <- function(g, centrality_fun = "centrality_eigen"){
data.frame(criteria = g %>% activate(edges) %>% pull(criteria) %>% unique()) %>%
mutate(sub_graphs = map(criteria, function(c){
g %>% as_data_frame() %>% filter(criteria == c) %>% as_tbl_graph(directed = F) %>%
activate(nodes) %>% mutate(centrality = get(centrality_fun)()) %>% data.frame()
})) %>%
unnest(sub_graphs) %>%
pivot_wider(names_from = "name", values_from = "centrality", values_fill = 0) %>%
column_to_rownames("criteria")
}
graph_all_gpt4 <- make_codiagnosis_graph(df_gpt4.0_codiag, n_diagnoses = top_n)
df_centr_gpt4 <- calculate_subgraph_centrality(graph_all_gpt4)
centrality_similarity <- function(data){
data %>%
rownames_to_column("criteria") %>%
format_criteria() %>%
column_to_rownames("criteria") %>%
as.matrix() %>%
t() %>%
lsa::cosine() %>%
as.data.frame() %>%
rownames_to_column("V1") %>%
pivot_longer(-V1, names_to = "V2", values_to = "cosine")
}
centrality_similarity(df_centr_gpt4)
centrality_wrapper <- function(data, n_diag=NULL){
make_codiagnosis_graph(data, n_diagnoses = n_diag) %>%
calculate_subgraph_centrality() %>%
centrality_similarity()
}
average_cosine_matrix <- listN(
df_gpt3.5_icd_codiag,
df_gpt4.0_icd_codiag,
df_claude3_haiku_t1.0_icd_codiag,
df_claude3_opus_t1.0_icd_codiag,
df_gemini1.0_pro_t1.0_icd_codiag,
df_gemini1.5_pro_t1.0_icd_codiag
) %>%
enframe(name = "model", value = "data") %>%
mutate(data = map(data, centrality_wrapper)) %>%
unnest(data) %>%
dplyr::summarise(cosine = mean(cosine), .by = c("V1", "V2")) %>%
pivot_wider(names_from = "V2", values_from = "cosine") %>%
column_to_rownames("V1") %>%
as.matrix()
average_cosine_matrix
SLE - SLICC SLE - EULAR-ACR MCAS - Consortium MCAS - Alternative
SLE - SLICC 1.0000000 0.8540815 0.2276693 0.5103618
SLE - EULAR-ACR 0.8540815 1.0000000 0.2682776 0.4819197
MCAS - Consortium 0.2276693 0.2682776 1.0000000 0.5459547
MCAS - Alternative 0.5103618 0.4819197 0.5459547 1.0000000
custom_heatmap <- function(data,
plot_title=NULL,
legend_title=NULL,
color_scale = NULL,
midpoint = NULL,
symmetric = T,
matrix_title_size=10,
matrix_names_size=8,
legend_title_size=10,
legend_label_size=8,
dendrograms=T,
dendrogram_weight = unit(10, "mm"),
legend_orientation = "vertical",
legend_length=NULL,
grid_lines=F
){
# Determin midpoint of data
scale_max <- ifelse(symmetric,max(abs(data)),max(data))
scale_min <- ifelse(symmetric,-max(abs(data)),min(data))
scale_mid <- scale_min + (scale_max - scale_min)/2
midpoint <- ifelse(is.null(midpoint), scale_mid, midpoint)
# Set default colorscales based on symmetry of data
if (is.null(color_scale) & symmetric){color_scale <- hcl.colors(3, "Earth")}
if (is.null(color_scale) & !symmetric){color_scale <- viridis::viridis(3)}
color_function <-circlize::colorRamp2(c(scale_min,midpoint,scale_max), color_scale)
# Legend parameters
legend_params <- list(
"title_gp" = grid::gpar(fontsize = legend_title_size, fontface = "bold"),
"labels_gp" = grid::gpar(fontsize = legend_label_size),
"direction" = legend_orientation
)
# Heatmap parameters
heatmap_arguments <- list(
"matrix" = data,
"col" = color_function,
"row_names_gp" = grid::gpar(fontsize = matrix_names_size),
"column_names_gp" = grid::gpar(fontsize = matrix_names_size),
"show_column_dend"=dendrograms,
"show_row_dend"=dendrograms
)
if(!is.null(legend_title)){heatmap_arguments[["name"]] <- legend_title}
if(grid_lines){heatmap_arguments[["rect_gp"]] <- grid::gpar(col = "black", lwd = 1)}
if(dendrograms){
heatmap_arguments[['column_dend_height']] <- dendrogram_weight
heatmap_arguments[['row_dend_width']] <- dendrogram_weight
}
legend_side <- ifelse(legend_orientation=="vertical","right","bottom")
if(legend_orientation=="vertical" &!is.null(legend_length)){
legend_params[['legend_height']] <- legend_length}
if(legend_orientation=="horizontal" &!is.null(legend_length)){
legend_params[['legend_width']] <- legend_length}
# Function call
heatmap_arguments[["heatmap_legend_param"]] <- legend_params
ht <- do.call(Heatmap, heatmap_arguments)
draw(ht, heatmap_legend_side=legend_side, align_heatmap_legend = "global_center")
}
custom_heatmap(average_cosine_matrix, symmetric = F, legend_title = "Cosine similarity", grid_lines = T, dendrograms = F, legend_orientation = "horizontal", legend_length=unit(10, "cm"))

df_comp <- listN(
df_gpt3.5_icd_codiag,
df_gpt4.0_icd_codiag,
df_claude3_haiku_t1.0_icd_codiag,
df_claude3_opus_t1.0_icd_codiag,
df_gemini1.0_pro_t1.0_icd_codiag,
df_gemini1.5_pro_t1.0_icd_codiag
) %>%
enframe(name = "model", value = "data") %>%
mutate(data = map(data, centrality_wrapper)) %>%
unnest(data)
cosine_similarity_compare <- function(df, pt_size=1,p_size=3){
Warning message:
In do_once((if (is_R_CMD_check()) stop else warning)("The function xfun::isFALSE() will be deprecated in the future. Please ", :
The function xfun::isFALSE() will be deprecated in the future. Please consider using base::isFALSE(x) or identical(x, FALSE) instead.
# Format data
df <- df %>%
unite(comp, V1, V2) %>%
filter(comp %in% c("MCAS - Consortium_MCAS - Alternative", "SLE - EULAR-ACR_SLE - SLICC")) %>%
mutate(comp = gsub("_", "\nvs. ", comp)) %>%
format_models()
# Plot data
df %>%
ggplot(aes(x = comp, y = cosine, color = model))+
geom_point(size=pt_size, position = position_dodge(width = 0.75))+
theme_bw() +
ggpubr::stat_compare_means(aes(group = comp), method = "wilcox.test", label = "p", vjust = 0.75, show.legend = F, size = p_size)+
theme(axis.text.x = element_text(angle =90, hjust =1)) +
labs(x=NULL, y="Cosine similarity") +
scale_color_brewer(palette = "Dark2") +
labs(color = "")
}
cosine_similarity_compare(df_comp)

cosine_similarity_compare(df_comp)

individual_cosine_matrix <- combine_data_frames(
df_gpt3.5_icd_codiag,
df_gpt4.0_icd_codiag,
df_claude3_haiku_t1.0_icd_codiag,
df_claude3_opus_t1.0_icd_codiag,
df_gemini1.0_pro_t1.0_icd_codiag,
df_gemini1.5_pro_t1.0_icd_codiag,
additional_function = function(x){
x %>%
make_codiagnosis_graph() %>%
calculate_subgraph_centrality() %>%
rownames_to_column("criteria") %>%
pivot_longer(-criteria, names_to="diagnosis", values_to="centrality")
}
) %>%
unite(criteria, original_df, criteria, sep = "-") %>%
pivot_wider(names_from = "diagnosis", values_from="centrality", values_fill=0) %>%
column_to_rownames("criteria") %>%
as.matrix() %>%
t() %>%
lsa::cosine() %>%
as.data.frame() %>%
rownames_to_column("V1") %>%
pivot_longer(-V1, names_to = "V2", values_to = "cosine") %>%
pivot_wider(names_from = "V2", values_from = "cosine") %>%
column_to_rownames("V1") %>%
as.matrix()
individual_cosine_matrix[1:5, 1:5]
df_gpt3.5_icd_codiag-slicc_sle df_gpt3.5_icd_codiag-eular_acr_sle df_gpt3.5_icd_codiag-mcas_consortium df_gpt3.5_icd_codiag-mcas_alternative
df_gpt3.5_icd_codiag-slicc_sle 1.0000000 0.8647922 0.2136086 0.4720033
df_gpt3.5_icd_codiag-eular_acr_sle 0.8647922 1.0000000 0.2643814 0.4613926
df_gpt3.5_icd_codiag-mcas_consortium 0.2136086 0.2643814 1.0000000 0.5519625
df_gpt3.5_icd_codiag-mcas_alternative 0.4720033 0.4613926 0.5519625 1.0000000
df_gpt4.0_icd_codiag-slicc_sle 0.8522184 0.7324445 0.1663721 0.3913603
df_gpt4.0_icd_codiag-slicc_sle
df_gpt3.5_icd_codiag-slicc_sle 0.8522184
df_gpt3.5_icd_codiag-eular_acr_sle 0.7324445
df_gpt3.5_icd_codiag-mcas_consortium 0.1663721
df_gpt3.5_icd_codiag-mcas_alternative 0.3913603
df_gpt4.0_icd_codiag-slicc_sle 1.0000000
alt_heatmap <- model_criteria_heatmap(individual_cosine_matrix,
color_scale = viridis::viridis(3),
title = " ",
metric = "Cosine\nsimilarity",
symmetric = F,
font_size = 8)
alt_heatmap

plt_alt <- cowplot::plot_grid(grid::grid.grabExpr(ComplexHeatmap::draw(alt_heatmap)))
plt_alt

ggsave(here("figures/4_alt_heatmap.pdf"), plot=plt_alt, height = 4, width = 6)
Final plot
Version 1
# n_diagnoses_bar <- 10
# n_diagnoses_abundance <- 50
# n_diagnoses_cumulative <- 50
title_size <- 9
label_size <- 6
legend_x_pad <- 0
legend_y_pad <- 0
apply_text_formatting <- list(
theme(
axis.text = element_text(size = label_size),
axis.title = element_text(size = title_size),
legend.text = element_text(size = label_size, margin=margin(0,0,0,r=1)),
strip.text = element_text(size = label_size + 1),
legend.key.height = unit(0.4, 'cm'),
legend.key.width = unit(0.4, 'cm'),
# legend.key = element_rect(size = margin(0,0,0,0)),
legend.box.background = element_rect(color = "black", size = 1),
legend.margin = margin(
t = legend_y_pad,
r = legend_x_pad+2,
b = legend_y_pad,
l = legend_x_pad
),
legend.key.spacing.y = unit(-1.5, "pt"),
legend.box.spacing = unit(1.0,"pt"),
axis.text.x=element_text(angle=45,hjust=1)
)
)
strip_margin <- 1
strip_formatting <- list(theme(
strip.text.x = element_text(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin)),
strip.text.y = element_text(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin))
# strip.background = element_rect(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin))
))
set.seed(1234)
plt_graph_icd <-
multi_make_codiagnosis_graph(
threshold_method = "average",
top_n = 100,
layout = "stress",
df_gpt3.5_codiag,
df_gpt4.0_codiag,
df_claude3_haiku_t1.0_codiag,
df_claude3_opus_t1.0_codiag,
df_gemini1.0_pro_t1.0_codiag,
df_gemini1.5_pro_t1.0_codiag,
point_size = 1.25,
border_size = 0.25,
edge_width = 0.5,
edge_alpha = 0.5,
label_text_size = 9,
tick_text_size = 6,
highlight_stroke_multiplier = 3,
legend_height = unit(25, "pt"),
legend_width = unit(10, "pt")
)
plt_edge_icd <- multi_edge_density_plot(
df_gpt3.5_icd_codiag,
df_gpt4.0_icd_codiag,
df_claude3_haiku_t1.0_icd_codiag,
df_claude3_opus_t1.0_icd_codiag,
df_gemini1.0_pro_t1.0_icd_codiag,
df_gemini1.5_pro_t1.0_icd_codiag
) +
apply_text_formatting +
theme(legend.position = "bottom", legend.direction = "horizontal") +
guides(color = guide_legend(override.aes = list(size = 1), ncol = 2))+
scale_y_continuous(expand = expansion(mult = c(0.1,0.1)))
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.
plt_heatmap_icd <-
custom_heatmap(
average_cosine_matrix,
symmetric = F,
legend_title = "Cosine similarity",
grid_lines = T,
dendrograms = T,
legend_orientation = "horizontal",
legend_length = unit(2, "cm"),
matrix_names_size = 6,
legend_title_size = 7.5,
legend_label_size = 6,
dendrogram_weight = unit(2, "mm")
)


plt_fig <- cowplot::plot_grid(
NULL,
cowplot::plot_grid(
NULL, plt_graph_icd, nrow=1, rel_widths=c(0.05,0.9)
),
NULL,
cowplot::plot_grid(
cowplot::plot_grid(NULL, plt_edge_icd ,rel_heights = c(0.1, 1), ncol = 1),
NULL,
cowplot::plot_grid(
NULL,
grid::grid.grabExpr(ComplexHeatmap::draw(plt_heatmap_icd, heatmap_legend_side = "bottom")),
NULL,
ncol = 1,
rel_heights = c(0.1, 1, 0.1)
),
nrow = 1,
rel_widths = c(0.5, 0.1, 0.6),
labels = c("B","","C"),
axis = 'h', align = 'bt'
),
ncol = 1,
rel_heights = c(0.05, 0.95, 0.01, 1),
labels = c("A")
)
plt_fig

Version 2
# n_diagnoses_bar <- 10
# n_diagnoses_abundance <- 50
# n_diagnoses_cumulative <- 50
title_size <- 9
label_size <- 6
legend_x_pad <- 0
legend_y_pad <- 0
apply_text_formatting <- list(
theme(
axis.text = element_text(size = label_size),
axis.title = element_text(size = title_size),
legend.text = element_text(size = label_size, margin=margin(0,0,0,r=1)),
strip.text = element_text(size = label_size + 1),
legend.key.height = unit(0.4, 'cm'),
legend.key.width = unit(0.4, 'cm'),
# legend.key = element_rect(size = margin(0,0,0,0)),
legend.box.background = element_rect(color = "black", size = 1),
legend.margin = margin(
t = legend_y_pad,
r = legend_x_pad+2,
b = legend_y_pad,
l = legend_x_pad
),
legend.key.spacing.y = unit(-1.5, "pt"),
legend.box.spacing = unit(1.0,"pt"),
axis.text.x=element_text(angle=90, vjust=0.5)
)
)
strip_margin <- 1
strip_formatting <- list(theme(
strip.text.x = element_text(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin)),
strip.text.y = element_text(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin))
# strip.background = element_rect(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin))
))
set.seed(1234)
plt_graph_icd <-
multi_make_codiagnosis_graph(
threshold_method = "average",
top_n = 100,
layout = "stress",
df_gpt3.5_codiag,
df_gpt4.0_codiag,
df_claude3_haiku_t1.0_codiag,
df_claude3_opus_t1.0_codiag,
df_gemini1.0_pro_t1.0_codiag,
df_gemini1.5_pro_t1.0_codiag,
point_size = 1.25,
border_size = 0.25,
edge_width = 0.5,
edge_alpha = 0.5,
label_text_size = 9,
tick_text_size = 6,
highlight_stroke_multiplier = 3,
legend_height = unit(25, "pt"),
legend_width = unit(10, "pt")
)
plt_edge_icd <- multi_edge_density_plot(
df_gpt3.5_icd_codiag,
df_gpt4.0_icd_codiag,
df_claude3_haiku_t1.0_icd_codiag,
df_claude3_opus_t1.0_icd_codiag,
df_gemini1.0_pro_t1.0_icd_codiag,
df_gemini1.5_pro_t1.0_icd_codiag
) +
apply_text_formatting +
# theme(legend.position = "bottom", legend.direction = "horizontal") +
guides(color = guide_legend(override.aes = list(size = 1), ncol = 2))+
scale_y_continuous(expand = expansion(mult = c(0.1,0.1)))
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.
plt_cosine <- cosine_similarity_compare(df_comp, p_size = 2) +
apply_text_formatting
plt_heatmap_icd <-
custom_heatmap(
average_cosine_matrix,
symmetric = F,
legend_title = "Average\ncosine similarity",
grid_lines = T,
dendrograms = T,
legend_orientation = "horizontal",
legend_length = unit(2.5, "cm"),
matrix_names_size = 6,
legend_title_size = 7.5,
legend_label_size = 6,
dendrogram_weight = unit(2.5, "mm")
)


pd <- -1
plt_fig <- cowplot::plot_grid(
#1
NULL,
#2
cowplot::plot_grid(
NULL, plt_graph_icd, nrow=1, rel_widths=c(0.05,0.9)
),
#3
NULL,
#4
cowplot::plot_grid(
#4.1
cowplot::plot_grid(
#4.1.1
plot_grid(
#4.1.1.1
plt_edge_icd+theme(legend.position = "none"),
#4.1.1.2
plt_cosine+theme(legend.position="none")+ylim(0.4,1),
# rel_widths = c(10,9),
nrow=1,
align="h",axis="bt"
),
#4.1.2
NA,
plot_grid(NULL,get_legend(plt_edge_icd),nrow=1,rel_widths=c(0.15,1)),
NA,
ncol=1,
rel_heights = c(1, 0.04, 0.1,0.1) #4.1._
),
#4.2
cowplot::plot_grid(
#4.2.1
NULL,
#4.2.2
grid::grid.grabExpr(ComplexHeatmap::draw(plt_heatmap_icd, heatmap_legend_side = "bottom", padding = unit(c(0,0,0,-1), "mm"))),
#4.2.3
NULL,
ncol = 1,
rel_heights = c(0.1, 1, 0.1)
),
nrow = 1,
rel_widths = c(0.6, 0.5), #4._
align = 'h', axis = 'bt'
),
ncol = 1,
rel_heights = c(0.05, 0.95, 0.05, 1)
)
Warning: Multiple components found; returning the first one. To return all, use `return_all = TRUE`.Warning: Cannot convert object of class logical into a grob.Warning: Cannot convert object of class logical into a grob.
plt_fig <- cowplot::ggdraw(plt_fig)+cowplot::draw_plot_label(c("A","B","C","D"), x=c(0,0,0.25,0.52), y=c(1,rep(0.52,3)))
plt_fig

ggsave(here("figures/4_Network_analysis.pdf"), plot=plt_fig, height = 5.5, width = 3.5)
LS0tCnRpdGxlOiAiQ28tZGlhZ25vc2lzIG5ldHdvcmsgYW5hbHlzaXMiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKYGBge3IsIG1lc3NhZ2UgPSBGfQpsaWJyYXJ5KGhlcmUpCnNvdXJjZShoZXJlKCJ1dGlscy9kYXRhX3Byb2Nlc3NpbmcuUiIpKQpzb3VyY2UoaGVyZSgidXRpbHMvZmlndXJlcy5SIikpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KCi0gR29hbCBpcyB0byBtb2RlbCBkaWFnbm9zZXMgZnJvbSBlYWNoIGNyaXRlcmlhIGJhc2VkIG9uIGhvdyBmcmVxdWVudGx5IHRoZXkgY28tb2NjdXIgdG9nZXRoZXIgd2l0aGluIGEgc2luZ2xlIDEwLXBvaW50IGRpZmZlcmVudGlhbCBkaWFnbm9zaXMgaXRlcmF0aW9uLgotIFRoZSByYXRpb25hbGUgaXMgdGhhdCBhbiBpZGVhbCBzZXQgb2YgY3JpdGVyaWEgd2lsbCB0ZW5kIHRvIHJlc3VsdCBpbiBhIHJlbGF0aXZlbHkgc2ltaWxhciBzZXQgb2YgZGlhZ25vc2VzIGluIGVhY2ggaXRlcmF0aW9uIGFuZCB0aHVzIGEgc21hbGwgc2V0IG9mIGhpZ2hseSBjby1vY2N1cnJpbmcgZGlhZ25vc2VzLgotIENvbnZlcnNlbHksIGEgcG9vciBzZXQgb2YgY3JpdGVyaWEgd2lsbCBnZW5lcmF0ZSBoaWdobHkgdmFyaWFibGUgZGlhZ25vc2VzIGluIGVhY2ggaXRlcmF0aW9uIGFuZCByYXRlcyBvZiBjby1vY2N1cnJlbmNlIHdpbGwgYmUgY29tcGFyYXRpdmVseSBsb3dlci4KCiMgSW1wb3J0IGFuZCBwcm9jZXNzIGRhdGEKCmBgYHtyLCBtZXNzYWdlID0gRn0KZGZfZ3B0My41IDwtIHJlYWRfbW9kZWwoImdwdC0zLjUtdHVyYm8tMTEwNiIsIGljZCA9IEZBTFNFKQpkZl9ncHQ0LjAgPC0gcmVhZF9tb2RlbCgiZ3B0LTQtdHVyYm8tcHJldmlldyIsIGljZCA9IEZBTFNFKQpkZl9jbGF1ZGUzX2hhaWt1X3QxLjAgPC0gcmVhZF9tb2RlbCgiY2xhdWRlLTMtaGFpa3UtMjAyNDAzMDdfdDEtMCIsIGljZCA9IEZBTFNFKQpkZl9jbGF1ZGUzX29wdXNfdDEuMCA8LSByZWFkX21vZGVsKCJjbGF1ZGUtMy1vcHVzLTIwMjQwMjI5X3QxLTAiLCBpY2QgPSBGQUxTRSkKZGZfZ2VtaW5pMS4wX3Byb190MS4wIDwtIHJlYWRfbW9kZWwoImdlbWluaS0xLjAtcHJvLTAwMl90MS0wIiwgaWNkID0gRkFMU0UpCmRmX2dlbWluaTEuNV9wcm9fdDEuMCA8LSByZWFkX21vZGVsKCJnZW1pbmktMS41LXByby0wMDFfdDEtMCIsIGljZCA9IEZBTFNFKQpgYGAKCmBgYHtyLCBtZXNzYWdlID0gRn0KZGZfZ3B0My41X2ljZCA8LSByZWFkX21vZGVsKCJncHQtMy41LXR1cmJvLTExMDYiLCBpY2QgPSBUUlVFKQpkZl9ncHQ0LjBfaWNkIDwtIHJlYWRfbW9kZWwoImdwdC00LXR1cmJvLXByZXZpZXciLCBpY2QgPSBUUlVFKQpkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkIDwtIHJlYWRfbW9kZWwoImNsYXVkZS0zLWhhaWt1LTIwMjQwMzA3X3QxLTAiLCBpY2QgPSBUUlVFKQpkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QgPC0gcmVhZF9tb2RlbCgiY2xhdWRlLTMtb3B1cy0yMDI0MDIyOV90MS0wIiwgaWNkID0gVFJVRSkKZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZCA8LSByZWFkX21vZGVsKCJnZW1pbmktMS4wLXByby0wMDJfdDEtMCIsIGljZCA9IFRSVUUpCmRmX2dlbWluaTEuNV9wcm9fdDEuMF9pY2QgPC0gcmVhZF9tb2RlbCgiZ2VtaW5pLTEuNS1wcm8tMDAxX3QxLTAiLCBpY2QgPSBUUlVFKQpgYGAKCmBgYHtyfQojIFRhbGx5IGVhY2ggcGFpciBvZiBjby1vY2N1cmluZyBkaWFnbm9zZXMgd2l0aGluIGVhY2ggY3JpdGVyaWEKIyBPcmlnaW5hbCByZXNwb25zZXMKZGZfZ3B0My41X2NvZGlhZyA8LSBjcmVhdGVfY29kaWFnbm9zaXNfZGYoZGZfZ3B0My41LCByZW1vdmVfc2luZ2xldG9ucyA9IFQpCmRmX2dwdDQuMF9jb2RpYWcgPC0gY3JlYXRlX2NvZGlhZ25vc2lzX2RmKGRmX2dwdDQuMCwgcmVtb3ZlX3NpbmdsZXRvbnMgPSBUKQpkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfY29kaWFnIDwtIGNyZWF0ZV9jb2RpYWdub3Npc19kZihkZl9jbGF1ZGUzX2hhaWt1X3QxLjAsIHJlbW92ZV9zaW5nbGV0b25zID0gVCkKZGZfY2xhdWRlM19vcHVzX3QxLjBfY29kaWFnIDwtIGNyZWF0ZV9jb2RpYWdub3Npc19kZihkZl9jbGF1ZGUzX29wdXNfdDEuMCwgcmVtb3ZlX3NpbmdsZXRvbnMgPSBUKQpkZl9nZW1pbmkxLjBfcHJvX3QxLjBfY29kaWFnIDwtIGNyZWF0ZV9jb2RpYWdub3Npc19kZihkZl9nZW1pbmkxLjBfcHJvX3QxLjAsIHJlbW92ZV9zaW5nbGV0b25zID0gVCkKZGZfZ2VtaW5pMS41X3Byb190MS4wX2NvZGlhZyA8LSBjcmVhdGVfY29kaWFnbm9zaXNfZGYoZGZfZ2VtaW5pMS41X3Byb190MS4wLCByZW1vdmVfc2luZ2xldG9ucyA9IFQpCmBgYAoKCmBgYHtyfQojIElDRCBjb252ZXJ0ZWQgcmVzcG9uc2VzCmRmX2dwdDMuNV9pY2RfY29kaWFnIDwtIGNyZWF0ZV9jb2RpYWdub3Npc19kZihkZl9ncHQzLjVfaWNkLCByZW1vdmVfc2luZ2xldG9ucyA9IFQpCmRmX2dwdDQuMF9pY2RfY29kaWFnIDwtIGNyZWF0ZV9jb2RpYWdub3Npc19kZihkZl9ncHQ0LjBfaWNkLCByZW1vdmVfc2luZ2xldG9ucyA9IFQpCmRmX2NsYXVkZTNfaGFpa3VfdDEuMF9pY2RfY29kaWFnIDwtIGNyZWF0ZV9jb2RpYWdub3Npc19kZihkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLCByZW1vdmVfc2luZ2xldG9ucyA9IFQpCmRmX2NsYXVkZTNfb3B1c190MS4wX2ljZF9jb2RpYWcgPC0gY3JlYXRlX2NvZGlhZ25vc2lzX2RmKGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwgcmVtb3ZlX3NpbmdsZXRvbnMgPSBUKQpkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkX2NvZGlhZyA8LSBjcmVhdGVfY29kaWFnbm9zaXNfZGYoZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZCwgcmVtb3ZlX3NpbmdsZXRvbnMgPSBUKQpkZl9nZW1pbmkxLjVfcHJvX3QxLjBfaWNkX2NvZGlhZyA8LSBjcmVhdGVfY29kaWFnbm9zaXNfZGYoZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZCwgcmVtb3ZlX3NpbmdsZXRvbnMgPSBUKQpgYGAKCgpgYGB7cn0KZGZfZ3B0NC4wX2NvZGlhZwpgYGAKCiMgR3JhcGggdmlzdWFsaXphdGlvbgoKIyMgRXhwbG9yaW5nIGxheW91dHMgCgotIFRvIGRldGVybWluZSBjbGVhcmVzdCB2aXN1YWxpemF0aW9uIG9mIG5vZGVzIGFuZCBlZGdlcwoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTYsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQojIFNlbGVjdGluZyBhIGxheW91dAp0b3BfbiA8LSAgMjAwCnNlZWQgPC0gMTIzNAoKbGF5b3V0cyA8LSBjKCJmciIsICJkaCIsICJrayIsICJzdHJlc3MiLCAiZ3JhcGhvcHQiKQoKZ3JhcGhfdG9wX2dwdDQgPC0gbWFrZV9jb2RpYWdub3Npc19ncmFwaChkZl9ncHQ0LjBfY29kaWFnLCBuX2RpYWdub3NlcyA9IHRvcF9uKQoKZm9yIChsIGluIGxheW91dHMpewogIHNldC5zZWVkKHNlZWQpCiAgcGx0IDwtIGNlbnRyYWxpdHlfZ3JhcGgoZ3JhcGhfdG9wX2dwdDQsIGxheW91dCA9IGwpCiAgcGx0IDwtIHBsdCArIGdndGl0bGUoIkdQVDQiLCBzdWJ0aXRsZSA9IHNwcmludGYoIkxheW91dCAlcyIsIGwpKQogIHByaW50KHBsdCkKfQoKYGBgCiMjIEluZGl2aWR1YWwgbW9kZWwgZGF0YQoKIyMjIE9yaWdpbmFsIHJlc3BvbnNlcwoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTYsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQp0b3BfbiA8LSAgMTAwCnNlZWQgPC0gMzIxCmdyYXBoX2xheW91dCA8LSAic3RyZXNzIgoKY29kaWFnX2dyYXBoX3dyYXBwZXIgPC0gZnVuY3Rpb24oZGF0YSl7CiAgc2V0LnNlZWQoc2VlZCkKICBkYXRhIDwtIG1ha2VfY29kaWFnbm9zaXNfZ3JhcGgoZGF0YSwgbl9kaWFnbm9zZXMgPSB0b3BfbikKICBjZW50cmFsaXR5X2dyYXBoKGRhdGEsIGxheW91dCA9IGdyYXBoX2xheW91dCkKfQoKY29kaWFnX2dyYXBoX3dyYXBwZXIoZGZfZ3B0My41X2NvZGlhZykrIGdndGl0bGUoIkNoYXRHUFQgMy41Iiwgc3VidGl0bGUgPSBzcHJpbnRmKCJUb3AgJXMiLCB0b3BfbikpCmNvZGlhZ19ncmFwaF93cmFwcGVyKGRmX2dwdDQuMF9jb2RpYWcpKyBnZ3RpdGxlKCJDaGF0R1BUIDQuMCIsIHN1YnRpdGxlID0gc3ByaW50ZigiVG9wICVzIiwgdG9wX24pKQpjb2RpYWdfZ3JhcGhfd3JhcHBlcihkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfY29kaWFnKSsgZ2d0aXRsZSgiQ2xhdWRlIDMgSGFpa3UiLCBzdWJ0aXRsZSA9IHNwcmludGYoIlRvcCAlcyIsIHRvcF9uKSkKY29kaWFnX2dyYXBoX3dyYXBwZXIoZGZfY2xhdWRlM19vcHVzX3QxLjBfY29kaWFnKSsgZ2d0aXRsZSgiQ2xhdWRlIDMgT3B1cyIsIHN1YnRpdGxlID0gc3ByaW50ZigiVG9wICVzIiwgdG9wX24pKQpjb2RpYWdfZ3JhcGhfd3JhcHBlcihkZl9nZW1pbmkxLjBfcHJvX3QxLjBfY29kaWFnKSsgZ2d0aXRsZSgiR2VtaW5pIDEuMCBQcm8iLCBzdWJ0aXRsZSA9IHNwcmludGYoIlRvcCAlcyIsIHRvcF9uKSkKY29kaWFnX2dyYXBoX3dyYXBwZXIoZGZfZ2VtaW5pMS41X3Byb190MS4wX2NvZGlhZykrIGdndGl0bGUoIkdlbWluaSAxLjUgUHJvIiwgc3VidGl0bGUgPSBzcHJpbnRmKCJUb3AgJXMiLCB0b3BfbikpCmBgYAojIyMgSUNEIGNvbnZlcnRlZCByZXNwb25lcwoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTYsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQpjb2RpYWdfZ3JhcGhfd3JhcHBlcihkZl9ncHQzLjVfaWNkX2NvZGlhZykrIGdndGl0bGUoIkNoYXRHUFQgMy41IElDRCIsIHN1YnRpdGxlID0gc3ByaW50ZigiVG9wICVzIiwgdG9wX24pKQpjb2RpYWdfZ3JhcGhfd3JhcHBlcihkZl9ncHQ0LjBfaWNkX2NvZGlhZykrIGdndGl0bGUoIkNoYXRHUFQgNC4wIElDRCIsIHN1YnRpdGxlID0gc3ByaW50ZigiVG9wICVzIiwgdG9wX24pKQpjb2RpYWdfZ3JhcGhfd3JhcHBlcihkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkX2NvZGlhZykrIGdndGl0bGUoIkNsYXVkZSAzIEhhaWt1IElDRCIsIHN1YnRpdGxlID0gc3ByaW50ZigiVG9wICVzIiwgdG9wX24pKQpjb2RpYWdfZ3JhcGhfd3JhcHBlcihkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2RfY29kaWFnKSsgZ2d0aXRsZSgiQ2xhdWRlIDMgT3B1cyBJQ0QiLCBzdWJ0aXRsZSA9IHNwcmludGYoIlRvcCAlcyIsIHRvcF9uKSkKY29kaWFnX2dyYXBoX3dyYXBwZXIoZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZF9jb2RpYWcpKyBnZ3RpdGxlKCJHZW1pbmkgMS4wIFBybyBJQ0QiLCBzdWJ0aXRsZSA9IHNwcmludGYoIlRvcCAlcyIsIHRvcF9uKSkKY29kaWFnX2dyYXBoX3dyYXBwZXIoZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZF9jb2RpYWcpKyBnZ3RpdGxlKCJHZW1pbmkgMS41IFBybyBJQ0QiLCBzdWJ0aXRsZSA9IHNwcmludGYoIlRvcCAlcyIsIHRvcF9uKSkKYGBgCgojIyBDb21iaW5lZCBtb2RlbCBkYXRhCgojIyMgT3JpZ2luYWwgcmVzcG9uc2VzCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Niwgd2FybmluZz1GLCBtZXNzYWdlPUZ9CnNldC5zZWVkKHNlZWQpCm11bHRpX21ha2VfY29kaWFnbm9zaXNfZ3JhcGgodGhyZXNob2xkX21ldGhvZCA9ICJpbmRpdmlkdWFsIiwgdG9wX24gPSAxMDAsIGxheW91dD0ic3RyZXNzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9ncHQzLjVfY29kaWFnLCBkZl9ncHQ0LjBfY29kaWFnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfY29kaWFnLCBkZl9jbGF1ZGUzX29wdXNfdDEuMF9jb2RpYWcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2NvZGlhZywgZGZfZ2VtaW5pMS41X3Byb190MS4wX2NvZGlhZykKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Niwgd2FybmluZz1GLCBtZXNzYWdlPUZ9Cm11bHRpX21ha2VfY29kaWFnbm9zaXNfZ3JhcGgodGhyZXNob2xkX21ldGhvZCA9ICJhdmVyYWdlIiwgdG9wX24gPSAxMDAsIGxheW91dD0ic3RyZXNzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9ncHQzLjVfY29kaWFnLCBkZl9ncHQ0LjBfY29kaWFnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfY29kaWFnLCBkZl9jbGF1ZGUzX29wdXNfdDEuMF9jb2RpYWcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2NvZGlhZywgZGZfZ2VtaW5pMS41X3Byb190MS4wX2NvZGlhZykKYGBgCiMjIyBJQ0QgY29udmVydGVkIHJlc3BvbnNlcwoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTYsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQpzZXQuc2VlZChzZWVkKQptdWx0aV9tYWtlX2NvZGlhZ25vc2lzX2dyYXBoKHRocmVzaG9sZF9tZXRob2QgPSAiaW5kaXZpZHVhbCIsIHRvcF9uID0gMTAwLCBsYXlvdXQ9InN0cmVzcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZfZ3B0My41X2ljZF9jb2RpYWcsIGRmX2dwdDQuMF9pY2RfY29kaWFnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkX2NvZGlhZywgZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkX2NvZGlhZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkX2NvZGlhZywgZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZF9jb2RpYWcpCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02LCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KbXVsdGlfbWFrZV9jb2RpYWdub3Npc19ncmFwaCh0aHJlc2hvbGRfbWV0aG9kID0gImF2ZXJhZ2UiLCB0b3BfbiA9IDEwMCwgbGF5b3V0PSJzdHJlc3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRmX2dwdDMuNV9pY2RfY29kaWFnLCBkZl9ncHQ0LjBfaWNkX2NvZGlhZywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZF9jb2RpYWcsIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZF9jb2RpYWcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZF9jb2RpYWcsIGRmX2dlbWluaTEuNV9wcm9fdDEuMF9pY2RfY29kaWFnKQpgYGAKCiMgRXZhbHVhdGUgZWRnZSBkZW5zaXR5CgotIEVkZ2UgZGVuc2l0eSByZXByZXNlbnRzIHRoZSB0b3RhbCBudW1iZXIgb2YgZWRnZXMgaW4gYSBncmFwaCByZWxhdGl2ZSB0byB0aGUgdG90YWwgbnVtYmVyIG9mICoqcG9zc2libGUqKiBlZGdlcyBpbiB0aGUgZ3JhcGgKICAtIFdoZW4gYWxsIHBvc3NpYmxlIGVkZ2VzIGFyZSBwcmVzZW50LCBlZGdlIGRlbnNpdHkgPSAxCiAgLSBXaGVuIG5vIGVkZ2VzIGFyZSBwcmVzZW50LCBlZGdlIGRlbnNpdHkgPSAwCi0gRGVuc2UgY28tb2NjdXJyZW5jZSBuZXR3b3JrcyByZXByZXNlbnQgY3JpdGVyaWEgdGhhdCBnZW5lcmF0ZSBoaWdobHkgcmVwcm9kdWNpYmxlIGRpYWdub3Nlcy4gQSBzcGFyc2UgY28tb2NjdXJyZW5jZSByZXByZXNlbnRzIGEgaGlnaCBkZWdyZWUgb2YgdmFyaWFiaWxpdHkgCgojIyBDb21iaW5lZCBtb2RlbCBkYXRhCgojIyMgT3JpZ2luYWwgcmVzcG9uc2VzCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9My41fQptdWx0aV9lZGdlX2RlbnNpdHlfcGxvdCgKICBkZl9ncHQzLjVfY29kaWFnLAogIGRmX2dwdDQuMF9jb2RpYWcsCiAgZGZfY2xhdWRlM19oYWlrdV90MS4wX2NvZGlhZywKICBkZl9jbGF1ZGUzX29wdXNfdDEuMF9jb2RpYWcsCiAgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2NvZGlhZywKICBkZl9nZW1pbmkxLjVfcHJvX3QxLjBfY29kaWFnCikgIAoKYGBgCgojIyMgSUNEIGNvbnZlcnRlZCByZXNwb25zZXMKCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0zLjV9CnBsdF9lZGdlX2ljZCA8LSBtdWx0aV9lZGdlX2RlbnNpdHlfcGxvdCgKICBkZl9ncHQzLjVfaWNkX2NvZGlhZywKICBkZl9ncHQ0LjBfaWNkX2NvZGlhZywKICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkX2NvZGlhZywKICBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2RfY29kaWFnLAogIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2RfY29kaWFnLAogIGRmX2dlbWluaTEuNV9wcm9fdDEuMF9pY2RfY29kaWFnCikgIApwbHRfZWRnZV9pY2QKcGx0X2VkZ2VfaWNkJGRhdGEgJT4lIHN1bW1hcmlzZShtZWFuKGVkZ2VfZGVuc2l0eSksIC5ieT0iY3JpdGVyaWEiKQpleHRyYWN0X2dncHVicl9wdmFsdWVzKHBsdF9lZGdlX2ljZCkKYGBgCgoKCiMgUGxvdCBjZW50cmFsaXR5CmBgYHtyfQpjYWxjdWxhdGVfc3ViZ3JhcGhfY2VudHJhbGl0eSA8LSBmdW5jdGlvbihnLCBjZW50cmFsaXR5X2Z1biA9ICJjZW50cmFsaXR5X2VpZ2VuIil7CiAgZGF0YS5mcmFtZShjcml0ZXJpYSA9IGcgJT4lIGFjdGl2YXRlKGVkZ2VzKSAlPiUgcHVsbChjcml0ZXJpYSkgJT4lIHVuaXF1ZSgpKSAlPiUgCiAgICBtdXRhdGUoc3ViX2dyYXBocyA9IG1hcChjcml0ZXJpYSwgZnVuY3Rpb24oYyl7CiAgICAgIGcgJT4lIGFzX2RhdGFfZnJhbWUoKSAlPiUgZmlsdGVyKGNyaXRlcmlhID09IGMpICU+JSBhc190YmxfZ3JhcGgoZGlyZWN0ZWQgPSBGKSAlPiUgCiAgICAgICAgYWN0aXZhdGUobm9kZXMpICU+JSBtdXRhdGUoY2VudHJhbGl0eSA9IGdldChjZW50cmFsaXR5X2Z1bikoKSkgJT4lIGRhdGEuZnJhbWUoKQogICAgfSkpICU+JSAKICB1bm5lc3Qoc3ViX2dyYXBocykgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAibmFtZSIsIHZhbHVlc19mcm9tID0gImNlbnRyYWxpdHkiLCB2YWx1ZXNfZmlsbCA9IDApICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoImNyaXRlcmlhIikKfQoKZ3JhcGhfYWxsX2dwdDQgPC0gbWFrZV9jb2RpYWdub3Npc19ncmFwaChkZl9ncHQ0LjBfY29kaWFnLCBuX2RpYWdub3NlcyA9IHRvcF9uKQpkZl9jZW50cl9ncHQ0IDwtIGNhbGN1bGF0ZV9zdWJncmFwaF9jZW50cmFsaXR5KGdyYXBoX2FsbF9ncHQ0KQpgYGAKCmBgYHtyfQpjZW50cmFsaXR5X3NpbWlsYXJpdHkgPC0gZnVuY3Rpb24oZGF0YSl7CiAgZGF0YSAlPiUgCiAgICByb3duYW1lc190b19jb2x1bW4oImNyaXRlcmlhIikgJT4lIAogICAgZm9ybWF0X2NyaXRlcmlhKCkgJT4lIAogICAgY29sdW1uX3RvX3Jvd25hbWVzKCJjcml0ZXJpYSIpICU+JSAKICAgIGFzLm1hdHJpeCgpICU+JSAKICAgIHQoKSAlPiUgCiAgICBsc2E6OmNvc2luZSgpICU+JSAKICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgICByb3duYW1lc190b19jb2x1bW4oIlYxIikgJT4lIAogICAgcGl2b3RfbG9uZ2VyKC1WMSwgbmFtZXNfdG8gPSAiVjIiLCB2YWx1ZXNfdG8gPSAiY29zaW5lIikKfQoKY2VudHJhbGl0eV9zaW1pbGFyaXR5KGRmX2NlbnRyX2dwdDQpCmBgYApgYGB7cn0KY2VudHJhbGl0eV93cmFwcGVyIDwtIGZ1bmN0aW9uKGRhdGEsIG5fZGlhZz1OVUxMKXsKICBtYWtlX2NvZGlhZ25vc2lzX2dyYXBoKGRhdGEsIG5fZGlhZ25vc2VzID0gbl9kaWFnKSAlPiUgCiAgICBjYWxjdWxhdGVfc3ViZ3JhcGhfY2VudHJhbGl0eSgpICU+JSAKICAgIGNlbnRyYWxpdHlfc2ltaWxhcml0eSgpCn0KCmF2ZXJhZ2VfY29zaW5lX21hdHJpeCA8LSBsaXN0TigKICBkZl9ncHQzLjVfaWNkX2NvZGlhZywKICBkZl9ncHQ0LjBfaWNkX2NvZGlhZywKICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkX2NvZGlhZywKICBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2RfY29kaWFnLAogIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2RfY29kaWFnLAogIGRmX2dlbWluaTEuNV9wcm9fdDEuMF9pY2RfY29kaWFnCikgJT4lCiAgZW5mcmFtZShuYW1lID0gIm1vZGVsIiwgdmFsdWUgPSAiZGF0YSIpICU+JQogIG11dGF0ZShkYXRhID0gbWFwKGRhdGEsIGNlbnRyYWxpdHlfd3JhcHBlcikpICU+JQogIHVubmVzdChkYXRhKSAlPiUKICBkcGx5cjo6c3VtbWFyaXNlKGNvc2luZSA9IG1lYW4oY29zaW5lKSwgLmJ5ID0gYygiVjEiLCAiVjIiKSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJWMiIsIHZhbHVlc19mcm9tID0gImNvc2luZSIpICU+JQogIGNvbHVtbl90b19yb3duYW1lcygiVjEiKSAlPiUKICBhcy5tYXRyaXgoKQoKYXZlcmFnZV9jb3NpbmVfbWF0cml4CgoKYGBgCgoKCmBgYHtyLCBmaWcud2lkdGg9NS41LCBmaWcuaGVpZ2h0PTMuNX0KY3VzdG9tX2hlYXRtYXAgPC0gZnVuY3Rpb24oZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfdGl0bGU9TlVMTCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF90aXRsZT1OVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3Jfc2NhbGUgPSBOVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSBOVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ltbWV0cmljID0gVCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdHJpeF90aXRsZV9zaXplPTEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRyaXhfbmFtZXNfc2l6ZT04LAogICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfdGl0bGVfc2l6ZT0xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX2xhYmVsX3NpemU9OCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVuZHJvZ3JhbXM9VCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVuZHJvZ3JhbV93ZWlnaHQgPSB1bml0KDEwLCAibW0iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX29yaWVudGF0aW9uID0gInZlcnRpY2FsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX2xlbmd0aD1OVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkX2xpbmVzPUYKICAgICAgICAgICAgICAgICAgICAgICAgICAgKXsKICAKICAjIERldGVybWluIG1pZHBvaW50IG9mIGRhdGEKICBzY2FsZV9tYXggPC0gaWZlbHNlKHN5bW1ldHJpYyxtYXgoYWJzKGRhdGEpKSxtYXgoZGF0YSkpCiAgc2NhbGVfbWluIDwtIGlmZWxzZShzeW1tZXRyaWMsLW1heChhYnMoZGF0YSkpLG1pbihkYXRhKSkKICBzY2FsZV9taWQgPC0gc2NhbGVfbWluICsgKHNjYWxlX21heCAtIHNjYWxlX21pbikvMgogIAogIG1pZHBvaW50IDwtIGlmZWxzZShpcy5udWxsKG1pZHBvaW50KSwgc2NhbGVfbWlkLCBtaWRwb2ludCkKICAKICAjIFNldCBkZWZhdWx0IGNvbG9yc2NhbGVzIGJhc2VkIG9uIHN5bW1ldHJ5IG9mIGRhdGEKICBpZiAoaXMubnVsbChjb2xvcl9zY2FsZSkgJiBzeW1tZXRyaWMpe2NvbG9yX3NjYWxlIDwtIGhjbC5jb2xvcnMoMywgIkVhcnRoIil9CiAgaWYgKGlzLm51bGwoY29sb3Jfc2NhbGUpICYgIXN5bW1ldHJpYyl7Y29sb3Jfc2NhbGUgPC0gdmlyaWRpczo6dmlyaWRpcygzKX0KICBjb2xvcl9mdW5jdGlvbiA8LWNpcmNsaXplOjpjb2xvclJhbXAyKGMoc2NhbGVfbWluLG1pZHBvaW50LHNjYWxlX21heCksIGNvbG9yX3NjYWxlKQogIAogICMgTGVnZW5kIHBhcmFtZXRlcnMKICBsZWdlbmRfcGFyYW1zIDwtIGxpc3QoCiAgICAgICJ0aXRsZV9ncCIgPSBncmlkOjpncGFyKGZvbnRzaXplID0gbGVnZW5kX3RpdGxlX3NpemUsIGZvbnRmYWNlID0gImJvbGQiKSwKICAgICAgImxhYmVsc19ncCIgPSBncmlkOjpncGFyKGZvbnRzaXplID0gbGVnZW5kX2xhYmVsX3NpemUpLAogICAgICAiZGlyZWN0aW9uIiA9IGxlZ2VuZF9vcmllbnRhdGlvbgogICAgICApCiAgCiAgIyBIZWF0bWFwIHBhcmFtZXRlcnMKICBoZWF0bWFwX2FyZ3VtZW50cyA8LSBsaXN0KAogICAgIm1hdHJpeCIgPSBkYXRhLAogICAgImNvbCIgPSBjb2xvcl9mdW5jdGlvbiwKICAgICJyb3dfbmFtZXNfZ3AiID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IG1hdHJpeF9uYW1lc19zaXplKSwKICAgICJjb2x1bW5fbmFtZXNfZ3AiID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IG1hdHJpeF9uYW1lc19zaXplKSwKICAgICJzaG93X2NvbHVtbl9kZW5kIj1kZW5kcm9ncmFtcywKICAgICJzaG93X3Jvd19kZW5kIj1kZW5kcm9ncmFtcwogICkKICAKICBpZighaXMubnVsbChsZWdlbmRfdGl0bGUpKXtoZWF0bWFwX2FyZ3VtZW50c1tbIm5hbWUiXV0gPC0gbGVnZW5kX3RpdGxlfQogIGlmKGdyaWRfbGluZXMpe2hlYXRtYXBfYXJndW1lbnRzW1sicmVjdF9ncCJdXSA8LSBncmlkOjpncGFyKGNvbCA9ICJibGFjayIsIGx3ZCA9IDEpfQogIGlmKGRlbmRyb2dyYW1zKXsKICAgIGhlYXRtYXBfYXJndW1lbnRzW1snY29sdW1uX2RlbmRfaGVpZ2h0J11dIDwtIGRlbmRyb2dyYW1fd2VpZ2h0CiAgICBoZWF0bWFwX2FyZ3VtZW50c1tbJ3Jvd19kZW5kX3dpZHRoJ11dIDwtIGRlbmRyb2dyYW1fd2VpZ2h0CiAgfQogIAogIGxlZ2VuZF9zaWRlIDwtIGlmZWxzZShsZWdlbmRfb3JpZW50YXRpb249PSJ2ZXJ0aWNhbCIsInJpZ2h0IiwiYm90dG9tIikKICBpZihsZWdlbmRfb3JpZW50YXRpb249PSJ2ZXJ0aWNhbCIgJiFpcy5udWxsKGxlZ2VuZF9sZW5ndGgpKXsKICAgIGxlZ2VuZF9wYXJhbXNbWydsZWdlbmRfaGVpZ2h0J11dIDwtIGxlZ2VuZF9sZW5ndGh9CiAgaWYobGVnZW5kX29yaWVudGF0aW9uPT0iaG9yaXpvbnRhbCIgJiFpcy5udWxsKGxlZ2VuZF9sZW5ndGgpKXsKICAgIGxlZ2VuZF9wYXJhbXNbWydsZWdlbmRfd2lkdGgnXV0gPC0gbGVnZW5kX2xlbmd0aH0KICAjIEZ1bmN0aW9uIGNhbGwKICBoZWF0bWFwX2FyZ3VtZW50c1tbImhlYXRtYXBfbGVnZW5kX3BhcmFtIl1dIDwtIGxlZ2VuZF9wYXJhbXMKICBodCA8LSBkby5jYWxsKEhlYXRtYXAsIGhlYXRtYXBfYXJndW1lbnRzKQogIGRyYXcoaHQsIGhlYXRtYXBfbGVnZW5kX3NpZGU9bGVnZW5kX3NpZGUsIGFsaWduX2hlYXRtYXBfbGVnZW5kID0gImdsb2JhbF9jZW50ZXIiKQogIAp9CgpjdXN0b21faGVhdG1hcChhdmVyYWdlX2Nvc2luZV9tYXRyaXgsIHN5bW1ldHJpYyA9IEYsIGxlZ2VuZF90aXRsZSA9ICJDb3NpbmUgc2ltaWxhcml0eSIsIGdyaWRfbGluZXMgPSBULCBkZW5kcm9ncmFtcyA9IEYsIGxlZ2VuZF9vcmllbnRhdGlvbiA9ICJob3Jpem9udGFsIiwgbGVnZW5kX2xlbmd0aD11bml0KDEwLCAiY20iKSkKYGBgCmBgYHtyfQpkZl9jb21wIDwtIGxpc3ROKAogIGRmX2dwdDMuNV9pY2RfY29kaWFnLAogIGRmX2dwdDQuMF9pY2RfY29kaWFnLAogIGRmX2NsYXVkZTNfaGFpa3VfdDEuMF9pY2RfY29kaWFnLAogIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZF9jb2RpYWcsCiAgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZF9jb2RpYWcsCiAgZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZF9jb2RpYWcKKSAlPiUKICBlbmZyYW1lKG5hbWUgPSAibW9kZWwiLCB2YWx1ZSA9ICJkYXRhIikgJT4lCiAgbXV0YXRlKGRhdGEgPSBtYXAoZGF0YSwgY2VudHJhbGl0eV93cmFwcGVyKSkgJT4lCiAgdW5uZXN0KGRhdGEpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0zLjUsIGZpZy5oZWlnaHQ9NH0KY29zaW5lX3NpbWlsYXJpdHlfY29tcGFyZSA8LSBmdW5jdGlvbihkZiwgcHRfc2l6ZT0xLHBfc2l6ZT0zKXsKICAjIEZvcm1hdCBkYXRhCiAgZGYgPC0gZGYgJT4lIAogICAgdW5pdGUoY29tcCwgVjEsIFYyKSAlPiUgCiAgICBmaWx0ZXIoY29tcCAlaW4lIGMoIk1DQVMgLSBDb25zb3J0aXVtX01DQVMgLSBBbHRlcm5hdGl2ZSIsICJTTEUgLSBFVUxBUi1BQ1JfU0xFIC0gU0xJQ0MiKSkgJT4lIAogICAgbXV0YXRlKGNvbXAgPSBnc3ViKCJfIiwgIlxudnMuICIsIGNvbXApKSAlPiUgIAogICAgZm9ybWF0X21vZGVscygpIAogIAogICMgUGxvdCBkYXRhCiAgZGYgJT4lIAogICAgZ2dwbG90KGFlcyh4ID0gY29tcCwgeSA9IGNvc2luZSwgY29sb3IgPSBtb2RlbCkpKwogICAgZ2VvbV9wb2ludChzaXplPXB0X3NpemUsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjc1KSkrCiAgICB0aGVtZV9idygpICsKICAgIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKGFlcyhncm91cCA9IGNvbXApLCBtZXRob2QgPSAid2lsY294LnRlc3QiLCBsYWJlbCA9ICJwIiwgdmp1c3QgPSAwLjc1LCBzaG93LmxlZ2VuZCA9IEYsIHNpemUgPSBwX3NpemUpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPTkwLCBoanVzdCA9MSkpICsKICAgIGxhYnMoeD1OVUxMLCB5PSJDb3NpbmUgc2ltaWxhcml0eSIpICsKICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgKwogICAgbGFicyhjb2xvciA9ICIiKQp9CmNvc2luZV9zaW1pbGFyaXR5X2NvbXBhcmUoZGZfY29tcCkKYGBgCgpgYGB7cn0KaW5kaXZpZHVhbF9jb3NpbmVfbWF0cml4IDwtIGNvbWJpbmVfZGF0YV9mcmFtZXMoCiAgZGZfZ3B0My41X2ljZF9jb2RpYWcsCiAgZGZfZ3B0NC4wX2ljZF9jb2RpYWcsCiAgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZF9jb2RpYWcsCiAgZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkX2NvZGlhZywKICBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkX2NvZGlhZywKICBkZl9nZW1pbmkxLjVfcHJvX3QxLjBfaWNkX2NvZGlhZywKICBhZGRpdGlvbmFsX2Z1bmN0aW9uID0gZnVuY3Rpb24oeCl7CiAgICB4ICU+JSAKICAgICAgbWFrZV9jb2RpYWdub3Npc19ncmFwaCgpICU+JSAKICAgICAgY2FsY3VsYXRlX3N1YmdyYXBoX2NlbnRyYWxpdHkoKSAlPiUgCiAgICAgIHJvd25hbWVzX3RvX2NvbHVtbigiY3JpdGVyaWEiKSAlPiUgCiAgICAgIHBpdm90X2xvbmdlcigtY3JpdGVyaWEsIG5hbWVzX3RvPSJkaWFnbm9zaXMiLCB2YWx1ZXNfdG89ImNlbnRyYWxpdHkiKQogIH0KKSAlPiUgCiAgdW5pdGUoY3JpdGVyaWEsIG9yaWdpbmFsX2RmLCBjcml0ZXJpYSwgc2VwID0gIi0iKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJkaWFnbm9zaXMiLCB2YWx1ZXNfZnJvbT0iY2VudHJhbGl0eSIsIHZhbHVlc19maWxsPTApICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoImNyaXRlcmlhIikgJT4lIAogIGFzLm1hdHJpeCgpICU+JSAKICAgIHQoKSAlPiUgCiAgICBsc2E6OmNvc2luZSgpICU+JSAKICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgICByb3duYW1lc190b19jb2x1bW4oIlYxIikgJT4lIAogICAgcGl2b3RfbG9uZ2VyKC1WMSwgbmFtZXNfdG8gPSAiVjIiLCB2YWx1ZXNfdG8gPSAiY29zaW5lIikgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAiVjIiLCB2YWx1ZXNfZnJvbSA9ICJjb3NpbmUiKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoIlYxIikgJT4lCiAgYXMubWF0cml4KCkKCmluZGl2aWR1YWxfY29zaW5lX21hdHJpeFsxOjUsIDE6NV0KYGBgCgpgYGB7ciwgZmlnLndpZHRoPTUuNSwgZmlnLmhlaWdodD0zLjV9CmFsdF9oZWF0bWFwIDwtIG1vZGVsX2NyaXRlcmlhX2hlYXRtYXAoaW5kaXZpZHVhbF9jb3NpbmVfbWF0cml4LCAKICAgICAgICAgICAgICAgIGNvbG9yX3NjYWxlID0gdmlyaWRpczo6dmlyaWRpcygzKSwgCiAgICAgICAgICAgICAgICB0aXRsZSA9ICIgIiwgCiAgICAgICAgICAgICAgICBtZXRyaWMgPSAiQ29zaW5lXG5zaW1pbGFyaXR5IiwgCiAgICAgICAgICAgICAgICBzeW1tZXRyaWMgPSBGLAogICAgICAgICAgICAgICAgZm9udF9zaXplID0gOCkgIAogIAoKYWx0X2hlYXRtYXAKYGBgCmBgYHtyLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD00fQpwbHRfYWx0IDwtIGNvd3Bsb3Q6OnBsb3RfZ3JpZChncmlkOjpncmlkLmdyYWJFeHByKENvbXBsZXhIZWF0bWFwOjpkcmF3KGFsdF9oZWF0bWFwKSkpCnBsdF9hbHQKYGBgCmBgYHtyfQpnZ3NhdmUoaGVyZSgiZmlndXJlcy80X2FsdF9oZWF0bWFwLnBkZiIpLCBwbG90PXBsdF9hbHQsIGhlaWdodCA9IDQsIHdpZHRoID0gNikKYGBgCgojIEZpbmFsIHBsb3QKCiMjIyBWZXJzaW9uIDEKYGBge3IsIGZpZy53aWR0aD0zLjUsIGZpZy5oZWlnaHQ9NS41fQojIG5fZGlhZ25vc2VzX2JhciA8LSAxMAojIG5fZGlhZ25vc2VzX2FidW5kYW5jZSA8LSA1MAojIG5fZGlhZ25vc2VzX2N1bXVsYXRpdmUgPC0gNTAKCnRpdGxlX3NpemUgPC0gOQpsYWJlbF9zaXplIDwtIDYKbGVnZW5kX3hfcGFkIDwtIDAKbGVnZW5kX3lfcGFkIDwtIDAKCmFwcGx5X3RleHRfZm9ybWF0dGluZyA8LSBsaXN0KAogIHRoZW1lKAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSBsYWJlbF9zaXplKSwKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHRpdGxlX3NpemUpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGxhYmVsX3NpemUsIG1hcmdpbj1tYXJnaW4oMCwwLDAscj0xKSksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSBsYWJlbF9zaXplICsgMSksCiAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC40LCAnY20nKSwKICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDAuNCwgJ2NtJyksCiAgICAjIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3Qoc2l6ZSA9ICBtYXJnaW4oMCwwLDAsMCkpLAogICAgbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDEpLAogICAgbGVnZW5kLm1hcmdpbiA9IG1hcmdpbigKICAgICAgdCA9IGxlZ2VuZF95X3BhZCwKICAgICAgciA9IGxlZ2VuZF94X3BhZCsyLAogICAgICBiID0gbGVnZW5kX3lfcGFkLAogICAgICBsID0gbGVnZW5kX3hfcGFkIAogICAgKSwKICAgIGxlZ2VuZC5rZXkuc3BhY2luZy55ID0gdW5pdCgtMS41LCAicHQiKSwKICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMS4wLCJwdCIpLAogICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LGhqdXN0PTEpCiAgKQopCgoKc3RyaXBfbWFyZ2luIDwtIDEKc3RyaXBfZm9ybWF0dGluZyA8LSBsaXN0KHRoZW1lKAogIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IHN0cmlwX21hcmdpbiwgciA9IHN0cmlwX21hcmdpbiwgYiA9IHN0cmlwX21hcmdpbiwgbCA9IHN0cmlwX21hcmdpbikpLCAKICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSBzdHJpcF9tYXJnaW4sIHIgPSBzdHJpcF9tYXJnaW4sIGIgPSBzdHJpcF9tYXJnaW4sIGwgPSBzdHJpcF9tYXJnaW4pKQogICMgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChtYXJnaW4gPSBtYXJnaW4odCA9IHN0cmlwX21hcmdpbiwgciA9IHN0cmlwX21hcmdpbiwgYiA9IHN0cmlwX21hcmdpbiwgbCA9IHN0cmlwX21hcmdpbikpCikpCgpzZXQuc2VlZCgxMjM0KQpwbHRfZ3JhcGhfaWNkIDwtCiAgbXVsdGlfbWFrZV9jb2RpYWdub3Npc19ncmFwaCgKICAgIHRocmVzaG9sZF9tZXRob2QgPSAiYXZlcmFnZSIsCiAgICB0b3BfbiA9IDEwMCwKICAgIGxheW91dCA9ICJzdHJlc3MiLAogICAgZGZfZ3B0My41X2NvZGlhZywKICAgIGRmX2dwdDQuMF9jb2RpYWcsCiAgICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfY29kaWFnLAogICAgZGZfY2xhdWRlM19vcHVzX3QxLjBfY29kaWFnLAogICAgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2NvZGlhZywKICAgIGRmX2dlbWluaTEuNV9wcm9fdDEuMF9jb2RpYWcsCiAgICBwb2ludF9zaXplID0gMS4yNSwKICAgIGJvcmRlcl9zaXplID0gMC4yNSwKICAgIGVkZ2Vfd2lkdGggPSAwLjUsCiAgICBlZGdlX2FscGhhID0gMC41LAogICAgbGFiZWxfdGV4dF9zaXplID0gOSwKICAgIHRpY2tfdGV4dF9zaXplID0gNiwKICAgIGhpZ2hsaWdodF9zdHJva2VfbXVsdGlwbGllciA9IDMsCiAgICBsZWdlbmRfaGVpZ2h0ID0gdW5pdCgyNSwgInB0IiksCiAgICBsZWdlbmRfd2lkdGggPSB1bml0KDEwLCAicHQiKQogICkgCgpwbHRfZWRnZV9pY2QgPC0gbXVsdGlfZWRnZV9kZW5zaXR5X3Bsb3QoCiAgZGZfZ3B0My41X2ljZF9jb2RpYWcsCiAgZGZfZ3B0NC4wX2ljZF9jb2RpYWcsCiAgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZF9jb2RpYWcsCiAgZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkX2NvZGlhZywKICBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkX2NvZGlhZywKICBkZl9nZW1pbmkxLjVfcHJvX3QxLjBfaWNkX2NvZGlhZwopICArCiAgYXBwbHlfdGV4dF9mb3JtYXR0aW5nICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAxKSwgbmNvbCA9IDIpKSsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAuMSwwLjEpKSkKCnBsdF9oZWF0bWFwX2ljZCA8LQogIGN1c3RvbV9oZWF0bWFwKAogICAgYXZlcmFnZV9jb3NpbmVfbWF0cml4LAogICAgc3ltbWV0cmljID0gRiwKICAgIGxlZ2VuZF90aXRsZSA9ICJDb3NpbmUgc2ltaWxhcml0eSIsCiAgICBncmlkX2xpbmVzID0gVCwKICAgIGRlbmRyb2dyYW1zID0gVCwKICAgIGxlZ2VuZF9vcmllbnRhdGlvbiA9ICJob3Jpem9udGFsIiwKICAgIGxlZ2VuZF9sZW5ndGggPSB1bml0KDIsICJjbSIpLAogICAgbWF0cml4X25hbWVzX3NpemUgPSA2LCAKICAgIGxlZ2VuZF90aXRsZV9zaXplID0gNy41LAogICAgbGVnZW5kX2xhYmVsX3NpemUgPSA2LAogICAgZGVuZHJvZ3JhbV93ZWlnaHQgPSB1bml0KDIsICJtbSIpCiAgKQoKCnBsdF9maWcgPC0gY293cGxvdDo6cGxvdF9ncmlkKAogIE5VTEwsIAogIGNvd3Bsb3Q6OnBsb3RfZ3JpZCgKICAgIE5VTEwsIHBsdF9ncmFwaF9pY2QsIG5yb3c9MSwgcmVsX3dpZHRocz1jKDAuMDUsMC45KQogICksCiAgTlVMTCwKICBjb3dwbG90OjpwbG90X2dyaWQoCiAgICBjb3dwbG90OjpwbG90X2dyaWQoTlVMTCwgcGx0X2VkZ2VfaWNkICxyZWxfaGVpZ2h0cyA9IGMoMC4xLCAxKSwgbmNvbCA9IDEpLAogICAgTlVMTCwKICAgIGNvd3Bsb3Q6OnBsb3RfZ3JpZCgKICAgICAgTlVMTCwKICAgICAgZ3JpZDo6Z3JpZC5ncmFiRXhwcihDb21wbGV4SGVhdG1hcDo6ZHJhdyhwbHRfaGVhdG1hcF9pY2QsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIikpLAogICAgICBOVUxMLAogICAgICBuY29sID0gMSwKICAgICAgcmVsX2hlaWdodHMgPSBjKDAuMSwgMSwgMC4xKQogICAgKSwKICAgIG5yb3cgPSAxLAogICAgcmVsX3dpZHRocyA9IGMoMC41LCAwLjEsIDAuNiksCiAgICBsYWJlbHMgPSBjKCJCIiwiIiwiQyIpLAogICAgYXhpcyA9ICdoJywgYWxpZ24gPSAnYnQnCiAgKSwKCiAgbmNvbCA9IDEsCiAgcmVsX2hlaWdodHMgPSBjKDAuMDUsIDAuOTUsIDAuMDEsIDEpLAogIGxhYmVscyA9IGMoIkEiKQopCgpwbHRfZmlnIApgYGAKCiMjIyBWZXJzaW9uIDIKYGBge3IsIGZpZy53aWR0aD0zLjUsIGZpZy5oZWlnaHQ9NS41fQojIG5fZGlhZ25vc2VzX2JhciA8LSAxMAojIG5fZGlhZ25vc2VzX2FidW5kYW5jZSA8LSA1MAojIG5fZGlhZ25vc2VzX2N1bXVsYXRpdmUgPC0gNTAKCnRpdGxlX3NpemUgPC0gOQpsYWJlbF9zaXplIDwtIDYKbGVnZW5kX3hfcGFkIDwtIDAKbGVnZW5kX3lfcGFkIDwtIDAKCmFwcGx5X3RleHRfZm9ybWF0dGluZyA8LSBsaXN0KAogIHRoZW1lKAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSBsYWJlbF9zaXplKSwKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHRpdGxlX3NpemUpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGxhYmVsX3NpemUsIG1hcmdpbj1tYXJnaW4oMCwwLDAscj0xKSksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSBsYWJlbF9zaXplICsgMSksCiAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC40LCAnY20nKSwKICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDAuNCwgJ2NtJyksCiAgICAjIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3Qoc2l6ZSA9ICBtYXJnaW4oMCwwLDAsMCkpLAogICAgbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDEpLAogICAgbGVnZW5kLm1hcmdpbiA9IG1hcmdpbigKICAgICAgdCA9IGxlZ2VuZF95X3BhZCwKICAgICAgciA9IGxlZ2VuZF94X3BhZCsyLAogICAgICBiID0gbGVnZW5kX3lfcGFkLAogICAgICBsID0gbGVnZW5kX3hfcGFkIAogICAgKSwKICAgIGxlZ2VuZC5rZXkuc3BhY2luZy55ID0gdW5pdCgtMS41LCAicHQiKSwKICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMS4wLCJwdCIpLAogICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTkwLCB2anVzdD0wLjUpCiAgKQopCgoKc3RyaXBfbWFyZ2luIDwtIDEKc3RyaXBfZm9ybWF0dGluZyA8LSBsaXN0KHRoZW1lKAogIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IHN0cmlwX21hcmdpbiwgciA9IHN0cmlwX21hcmdpbiwgYiA9IHN0cmlwX21hcmdpbiwgbCA9IHN0cmlwX21hcmdpbikpLCAKICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSBzdHJpcF9tYXJnaW4sIHIgPSBzdHJpcF9tYXJnaW4sIGIgPSBzdHJpcF9tYXJnaW4sIGwgPSBzdHJpcF9tYXJnaW4pKQogICMgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChtYXJnaW4gPSBtYXJnaW4odCA9IHN0cmlwX21hcmdpbiwgciA9IHN0cmlwX21hcmdpbiwgYiA9IHN0cmlwX21hcmdpbiwgbCA9IHN0cmlwX21hcmdpbikpCikpCgpzZXQuc2VlZCgxMjM0KQpwbHRfZ3JhcGhfaWNkIDwtCiAgbXVsdGlfbWFrZV9jb2RpYWdub3Npc19ncmFwaCgKICAgIHRocmVzaG9sZF9tZXRob2QgPSAiYXZlcmFnZSIsCiAgICB0b3BfbiA9IDEwMCwKICAgIGxheW91dCA9ICJzdHJlc3MiLAogICAgZGZfZ3B0My41X2NvZGlhZywKICAgIGRmX2dwdDQuMF9jb2RpYWcsCiAgICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfY29kaWFnLAogICAgZGZfY2xhdWRlM19vcHVzX3QxLjBfY29kaWFnLAogICAgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2NvZGlhZywKICAgIGRmX2dlbWluaTEuNV9wcm9fdDEuMF9jb2RpYWcsCiAgICBwb2ludF9zaXplID0gMS4yNSwKICAgIGJvcmRlcl9zaXplID0gMC4yNSwKICAgIGVkZ2Vfd2lkdGggPSAwLjUsCiAgICBlZGdlX2FscGhhID0gMC41LAogICAgbGFiZWxfdGV4dF9zaXplID0gOSwKICAgIHRpY2tfdGV4dF9zaXplID0gNiwKICAgIGhpZ2hsaWdodF9zdHJva2VfbXVsdGlwbGllciA9IDMsCiAgICBsZWdlbmRfaGVpZ2h0ID0gdW5pdCgyNSwgInB0IiksCiAgICBsZWdlbmRfd2lkdGggPSB1bml0KDEwLCAicHQiKQogICkgCgpwbHRfZWRnZV9pY2QgPC0gbXVsdGlfZWRnZV9kZW5zaXR5X3Bsb3QoCiAgZGZfZ3B0My41X2ljZF9jb2RpYWcsCiAgZGZfZ3B0NC4wX2ljZF9jb2RpYWcsCiAgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZF9jb2RpYWcsCiAgZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkX2NvZGlhZywKICBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkX2NvZGlhZywKICBkZl9nZW1pbmkxLjVfcHJvX3QxLjBfaWNkX2NvZGlhZwopICArCiAgYXBwbHlfdGV4dF9mb3JtYXR0aW5nICsKICAjIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDEpLCBuY29sID0gMikpKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMC4xLDAuMSkpKQoKcGx0X2Nvc2luZSA8LSBjb3NpbmVfc2ltaWxhcml0eV9jb21wYXJlKGRmX2NvbXAsIHBfc2l6ZSA9IDIpICsKICBhcHBseV90ZXh0X2Zvcm1hdHRpbmcKCnBsdF9oZWF0bWFwX2ljZCA8LQogIGN1c3RvbV9oZWF0bWFwKAogICAgYXZlcmFnZV9jb3NpbmVfbWF0cml4LAogICAgc3ltbWV0cmljID0gRiwKICAgIGxlZ2VuZF90aXRsZSA9ICJBdmVyYWdlXG5jb3NpbmUgc2ltaWxhcml0eSIsCiAgICBncmlkX2xpbmVzID0gVCwKICAgIGRlbmRyb2dyYW1zID0gVCwKICAgIGxlZ2VuZF9vcmllbnRhdGlvbiA9ICJob3Jpem9udGFsIiwKICAgIGxlZ2VuZF9sZW5ndGggPSB1bml0KDIuNSwgImNtIiksCiAgICBtYXRyaXhfbmFtZXNfc2l6ZSA9IDYsIAogICAgbGVnZW5kX3RpdGxlX3NpemUgPSA3LjUsCiAgICBsZWdlbmRfbGFiZWxfc2l6ZSA9IDYsCiAgICBkZW5kcm9ncmFtX3dlaWdodCA9IHVuaXQoMi41LCAibW0iKQogICkKCnBkIDwtIC0xCgpwbHRfZmlnIDwtIGNvd3Bsb3Q6OnBsb3RfZ3JpZCgKICAjMQogIE5VTEwsIAogICMyCiAgY293cGxvdDo6cGxvdF9ncmlkKAogICAgTlVMTCwgcGx0X2dyYXBoX2ljZCwgbnJvdz0xLCByZWxfd2lkdGhzPWMoMC4wNSwwLjkpCiAgKSwKICAjMwogIE5VTEwsCiAgIzQKICBjb3dwbG90OjpwbG90X2dyaWQoCiAgICAjNC4xCiAgICBjb3dwbG90OjpwbG90X2dyaWQoCiAgICAgICM0LjEuMQogICAgICBwbG90X2dyaWQoCiAgICAgICAgIzQuMS4xLjEKICAgICAgICBwbHRfZWRnZV9pY2QrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSwKICAgICAgICAjNC4xLjEuMgogICAgICAgIHBsdF9jb3NpbmUrdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikreWxpbSgwLjQsMSksIAogICAgICAgICMgcmVsX3dpZHRocyA9IGMoMTAsOSksCiAgICAgICAgbnJvdz0xLAogICAgICAgIGFsaWduPSJoIixheGlzPSJidCIKICAgICAgICApLAogICAgICAjNC4xLjIKICAgICAgTkEsCiAgICAgIHBsb3RfZ3JpZChOVUxMLGdldF9sZWdlbmQocGx0X2VkZ2VfaWNkKSxucm93PTEscmVsX3dpZHRocz1jKDAuMTUsMSkpLAogICAgICBOQSwKICAgICAgbmNvbD0xLAogICAgICByZWxfaGVpZ2h0cyA9IGMoMSwgMC4wNCwgMC4xLDAuMSkgIzQuMS5fCiAgICApLAogICAgIzQuMgogICAgY293cGxvdDo6cGxvdF9ncmlkKAogICAgICAjNC4yLjEKICAgICAgTlVMTCwKICAgICAgIzQuMi4yCiAgICAgIGdyaWQ6OmdyaWQuZ3JhYkV4cHIoQ29tcGxleEhlYXRtYXA6OmRyYXcocGx0X2hlYXRtYXBfaWNkLCBoZWF0bWFwX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIsIHBhZGRpbmcgPSB1bml0KGMoMCwwLDAsLTEpLCAibW0iKSkpLAogICAgICAjNC4yLjMKICAgICAgTlVMTCwKICAgICAgbmNvbCA9IDEsCiAgICAgIHJlbF9oZWlnaHRzID0gYygwLjEsIDEsIDAuMSkKICAgICksCiAgICBucm93ID0gMSwKICAgIHJlbF93aWR0aHMgPSBjKDAuNiwgIDAuNSksICM0Ll8KICAgIGFsaWduID0gJ2gnLCBheGlzID0gJ2J0JwogICksCgogIG5jb2wgPSAxLAogIHJlbF9oZWlnaHRzID0gYygwLjA1LCAwLjk1LCAwLjA1LCAxKQopCgpwbHRfZmlnIDwtIGNvd3Bsb3Q6OmdnZHJhdyhwbHRfZmlnKStjb3dwbG90OjpkcmF3X3Bsb3RfbGFiZWwoYygiQSIsIkIiLCJDIiwiRCIpLCB4PWMoMCwwLDAuMjUsMC41MiksIHk9YygxLHJlcCgwLjUyLDMpKSkKcGx0X2ZpZyAKYGBgCgoKYGBge3IsIGV2YWw9Rn0KZ2dzYXZlKGhlcmUoImZpZ3VyZXMvNF9OZXR3b3JrX2FuYWx5c2lzLnBkZiIpLCBwbG90PXBsdF9maWcsIGhlaWdodCA9IDUuNSwgd2lkdGggPSAzLjUpCmBgYAoK